package org.itzixi.netty.websocket;


import cn.hutool.core.util.StrUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.itzixi.enums.MsgTypeEnum;
import org.itzixi.grace.result.GraceJSONResult;
import org.itzixi.netty.single.ChannelGroupSingleton;
import org.itzixi.netty.strategy.MessageHandlerStrategy;
import org.itzixi.netty.utils.JedisPoolUtils;
import org.itzixi.netty.utils.PropertiesUtils;
import org.itzixi.netty.utils.ZKUtil;
import org.itzixi.pojo.netty.ChatMsg;
import org.itzixi.pojo.netty.DataContent;
import org.itzixi.pojo.netty.NettyServerNode;
import org.itzixi.utils.JsonUtils;
import org.itzixi.utils.OkHttpUtil;
import redis.clients.jedis.Jedis;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

/**
 * 创建自定义助手类
 *
 * TextWebSocketFrame 用于为websocket专门处理的文本数据对象
 */
@Slf4j
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

//    public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static final ChannelGroup channelGroup = ChannelGroupSingleton.getInstance();
    private static final Properties properties = PropertiesUtils.getInstance();

    private final Jedis jedis = JedisPoolUtils.getJedis();


    @Override
    protected void channelRead0(ChannelHandlerContext ctx,
                                TextWebSocketFrame msg) throws Exception {
        // 获得客户端传输过来的消息
        String content = msg.text();
        Channel currentChannel = ctx.channel();
        String currentChannelId = currentChannel.id().asLongText();
        log.info("接收到的数据：{}", content);
        // 解析客户端发过来的消息
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        assert dataContent != null;
        dataContent.setExtend(currentChannelId);
        ChatMsg chatMsg = dataContent.getChatMsg();
        chatMsg.setChatTime(LocalDateTime.now());

        // 判断是不是互为黑名单好友，如果是则禁止发送
        // todo 服务器上改为内网地址
        // String friendId1st, String friendId2nd
        if (!Objects.equals(chatMsg.getMsgType(), MsgTypeEnum.CONNECT_INIT.type)){
            String isBlackUrl = properties.getProperty("chat.friend.isBlack.url");
            String url = StrUtil.format("{}?friendId1st={}&friendId2nd={}",isBlackUrl, chatMsg.getSenderId(), chatMsg.getReceiverId());
            log.info("远程黑名单接口是：{}", url);
            GraceJSONResult graceJSONResult = OkHttpUtil.get(url);
            if (graceJSONResult.getSuccess()){

                Boolean friendlyFlag = (Boolean) graceJSONResult.getData();
                log.info("远程调用黑名单接口成功，用户1：{}, 用户2：{},是否为好友：{}", chatMsg.getReceiverId(), chatMsg.getSenderId(), friendlyFlag);
                if (friendlyFlag)
                    return;
            }
        }

        // 判断消息类型，处理不同的业务
        Map<String, Object> dataContentMap = new HashMap<String, Object>(4){{
            put("dataContent", dataContent);
            put("channel", currentChannel);

        }};
        MessageHandlerStrategy.handleMsgByType(dataContentMap);
//
//        String message = chatMsg.getMsg();
//        String receiverId = chatMsg.getReceiverId();
//        String senderId = chatMsg.getSenderId();
//        Integer msgType = chatMsg.getMsgType();


//
//        if (Objects.equals(MsgTypeEnum.CONNECT_INIT.type, msgType)){
//            // 把channel和userId关联起来
//            UserChannelCache.putMultiChannels(senderId, currentChannel);
//            log.info("用户id是：{}, 对应的channelList是：{}", senderId, UserChannelCache.getMultiChannels(senderId));
//            UserChannelCache.putChannelOfUser(currentChannelId, senderId);
//        } else if(Objects.equals(MsgTypeEnum.WORDS.type, msgType)){
//            List<Channel> receiveChannelList = UserChannelCache.getMultiChannels(receiverId);
//            if (CollectionUtils.isEmpty(receiveChannelList)){
//                // 如果为空则表示断线或者离线状态
//                chatMsg.setIsReceiverOnLine(false);
//            } else {
//                chatMsg.setIsReceiverOnLine(true);
//
//            }
//        }




    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Channel currentChannel = ctx.channel();
        String currentChannelId = currentChannel.id().asLongText();
        log.info("服务端发生异常，channel对应的长id为:{}", currentChannelId);
        cause.printStackTrace();
        log.error("异常信息：{}", cause.getMessage() );
        // 移除多余的会话
        String userId = UserChannelCache.getUserIdByChannelId(currentChannelId);
        UserChannelCache.removeUselessChannels(userId, currentChannelId);
        currentChannel.close();

        channelGroup.remove(currentChannel);
        this.decrementOnlineCount(userId);
    }

    /**
     * 客户端连接之后
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel currentChannel = ctx.channel();
        String currentChannelId = currentChannel.id().asLongText();
        log.info("客户端建立连接，channel对应的长id为:{}", currentChannelId);
        // 获得客户端的channel，存入到ChannelGroup中管理
        channelGroup.add(currentChannel);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel currentChannel = ctx.channel();
        String currentChannelId = currentChannel.id().asLongText();
        log.info("客户端关闭连接，channel对应的长id为:{}", currentChannelId);
        // 移除多余的会话
        String userId = UserChannelCache.getUserIdByChannelId(currentChannelId);
        UserChannelCache.removeUselessChannels(userId, currentChannelId);
        channelGroup.remove(currentChannel);
        this.decrementOnlineCount(userId);
    }

    private void decrementOnlineCount(String userId){
        // 断线之后在线人数减少

        String nettNodeJsonStr = jedis.get(userId);
        NettyServerNode minNode = JsonUtils.jsonToPojo(nettNodeJsonStr, NettyServerNode.class);
        ZKUtil.decrementOnlineCount(minNode);
    }
}
